#pragma once
#include "util.hpp"
#include "log.hpp"
#include <stdio.h>
#include <string>
#include <mutex>

class data_manager// 数据管理器
{
public:
    data_manager()
    {
        // 1. 初始化mysql得到MYSQL句柄
        _mysql = mysql_util::init();
        if (_mysql == nullptr)
        {
            ERROR_LOG("mysql初始化失败！得到的MYSQL句柄为空！");
            exit(-1);
        }
    }

    bool user_register(Json::Value &root)// 管理用户注册的数据
    {
        // 1. 用户名或者密码为空，注册失败
        if (root["username"].asString().empty() || root["password"].asString().empty())
        {
            DEBUG_LOG("用户名或密码为空！注册失败！");
            return false;
        }
        // 2. 执行sql语句
        char sql_buffer[1024] = {0};
        sprintf(sql_buffer, "insert into user_table (user_name,user_password,score,total_count,win_count) values('%s',password('%s'),1000,0,0);",
                root["username"].asCString(), root["password"].asCString());// 向user_table表中插入信息的sql语句
        bool ret = mysql_util::query(_mysql,sql_buffer);// 执行sql语句
        if(ret == false)
        {
            DEBUG_LOG("用户注册失败！原因:sql语句执行不成功！");
            return false;
        }
        return true;
    }

    bool user_login(Json::Value &root)// 用户登录需要处理的数据
    {
        //1. 判断用户名或密码是否为空
        if (root["username"].asString().empty() || root["password"].asString().empty())
        {
            DEBUG_LOG("用户名或密码为空！注册失败！");
            return false;
        }
        //2. 从数据库获取信息作对比
        //2.1 执行查询sql语句
        char sql_buffer[1024] = {0};
        sprintf(sql_buffer, "select id,user_name,score,total_count,win_count from user_table where user_name='%s' and user_password=password('%s');",
                root["username"].asCString(),root["password"].asCString());// 根据指定的用户名查询指定的用户信息
        bool ret = mysql_util::query(_mysql,sql_buffer);
        if(ret == false)
        {
            DEBUG_LOG("用户登陆失败！原因:sql语句执行不成功！");
            return false;
        }

        //2.2 将查询结果保存到本地
        MYSQL_RES *result = nullptr;// 指向结果集的指针
        {
            std::unique_lock<std::mutex> lock(_mutex);
            result = mysql_store_result(_mysql);// 获取结果集
            if(result == nullptr)
            {
                DEBUG_LOG("用户登陆失败！原因：获取MYSQL_RES句柄失败！");
                return false;
            }
            // 获取结果集成功
            int n = mysql_num_rows(result);// 获取结果集的条目数量
            if(n != 1)
            {
                DEBUG_LOG("用户登录失败！原因：存在多份相同的信息！");
                return false;
            }
        }
        MYSQL_ROW row = mysql_fetch_row(result);// 捕捉结果集
        root["uid"] = (Json::Int64)std::stol(row[0]);
        root["username"] = row[1];
        root["socre"] = (Json::Int64)std::stol(row[2]);
        root["total_count"] = (Json::Int64)std::stol(row[3]);
        root["win_count"] = (Json::Int64)std::stol(row[4]);
        return true;
    }

    bool user_win(uint64_t uid)// 玩家胜利之后需要处理的数据
    {
        //1. 执行sql语句
        char sql_buffer[1024] = {0};
        sprintf(sql_buffer, "update user_table set score=score+30,total_count=total_count+1,win_count=win_count+1 where id='%d';",
            uid);
        bool ret = mysql_util::query(_mysql,sql_buffer);
        if(ret == false)
        {
            DEBUG_LOG("玩家胜利数据库更新失败！原因：sql语句执行不成功！");
            return false;
        }
        return true;
    }

    bool user_lose(uint64_t uid)// 玩家失败后需要处理的数据
    {
        //1. 执行sql语句
        char sql_buffer[1024] = {0};
        sprintf(sql_buffer, "update user_table set score=score-30,total_count=total_count+1 where id='%d';",
            uid);
        bool ret = mysql_util::query(_mysql,sql_buffer);
        if(ret == false)
        {
            DEBUG_LOG("玩家失败数据库更新失败！原因：sql语句执行不成功！");
            return false;
        }
        return true;
    }

    bool user_info_by_name(const std::string &name,Json::Value &out)// 根据用户名获取玩家信息,结果保存在Json::Value对象中
    {
        //1. 判断外部传入的用户名是否为空
        if(name.empty())
        {
            DEBUG_LOG("获取玩家信息失败！原因：传入的用户名为空！");
            return false;
        }
        //2. 执行sql语句
        char sql_buffer[1024] = {0};
        sprintf(sql_buffer, "select id,user_name,score,total_count,win_count from user_table where user_name='%s';",
            name.c_str());
        bool ret = mysql_util::query(_mysql,sql_buffer);
        if(ret == false)
        {
            DEBUG_LOG("根据用户名获取玩家信息失败！原因:sql语句执行不成功！");
            return false;
        }
        MYSQL_RES *result = nullptr;// 指向结果集的指针
        //3. 将结果保存到本地
        {
            std::unique_lock<std::mutex> lock(_mutex);
            result = mysql_store_result(_mysql);// 获取结果集
            if(result == nullptr)
            {
                DEBUG_LOG("根据用户名获取玩家信息失败！原因：获取MYSQL_RES句柄失败！");
                return false;
            }
            int n = mysql_num_rows(result);// 结果应该只有一条
            if(n != 1)
            {
                DEBUG_LOG("根据用户名获取玩家信息失败！原因：存在多份相同的信息！");
                return false;
            }
        }
        MYSQL_ROW row = mysql_fetch_row(result);// 结果集放到MYSQL_ROW对象当中
        out["uid"] = (Json::Int64)std::stol(row[0]);
        out["username"] = row[1];
        out["socre"] = (Json::Int64)std::stol(row[2]);
        out["total_count"] = (Json::Int64)std::stol(row[3]);
        out["win_count"] = (Json::Int64)std::stol(row[4]);
        return true;
    }

    bool user_info_by_id(uint64_t uid,Json::Value &out)// 根据用户id获取信息
    {
        //1. 执行sql语句
        char sql_buffer[1024] = {0};
        sprintf(sql_buffer, "select id,user_name,score,total_count,win_count from user_table where id='%d';",
            uid);
        bool ret = mysql_util::query(_mysql,sql_buffer);
        if(ret == false)
        {
            DEBUG_LOG("根据uid获取玩家信息失败！原因:sql语句执行不成功！");
            return false;
        }
        //3. 将结果保存到本地
        MYSQL_RES *result = nullptr;
        {
            std::unique_lock<std::mutex> lock(_mutex);
            result = mysql_store_result(_mysql);
            if(result == nullptr)
            {
                DEBUG_LOG("根据uid获取玩家信息失败！原因：获取MYSQL_RES句柄失败！");
                return false;
            }
            int n = mysql_num_rows(result);
            if(n != 1)
            {
                DEBUG_LOG("根据uid获取玩家信息失败！原因：存在多份相同的信息！");
                return false;
            }
        }
        MYSQL_ROW row = mysql_fetch_row(result);
        out["uid"] = (Json::Int64)std::stol(row[0]);
        out["username"] = row[1];
        out["score"] = (Json::Int64)std::stol(row[2]);
        out["total_count"] = (Json::Int64)std::stol(row[3]);
        out["win_count"] = (Json::Int64)std::stol(row[4]);
        return true;
    }
protected:
    MYSQL *_mysql;// mysql句柄
    std::mutex _mutex;// 无法保证一定是线程安全的
    /*MySQL提供的接口都是线程安全的，为什么还需要再加一次锁呢？
    原因：如果有多个线程同时执行mysql_store_result语句，那么只有一个线程真实执行它，其他线程都会陷入阻塞，
    如果那个线程实行mysql_store_result完毕之后后续立马对数据库进行修改，那么后续执行mysql_store_result的线程
    所获取到的结果集就不是所预期的(至少对于本项目来说是这样的)*/
};





